﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;
using System.Windows.Threading;
using System.IO;
using System.Timers;

namespace GUI_MKII
{ 
    public partial class MainWindow : Window
    {
        enum DisplayModes { Beginning=0, Normal, Minimal, GeoCache, End };

        #region GUI Colors
        /// <summary>
        /// Variables controlling color of GUI elements
        /// Please provide a DependencyProperty for each item
        ///   You can do this by typing "depprop" + TAB + TAB
        /// </summary>
        ///

        // Text color for GUI elements (also foreground) 
        public Brush color_Text
        {
            get { return (Brush)GetValue(property_color_Text); }
            set { SetValue(property_color_Text, value); }
        }
        public static readonly DependencyProperty property_color_Text =
            DependencyProperty.Register(
            "color_Text", typeof(Brush), typeof(MainWindow), 
            new UIPropertyMetadata(Brushes.Lime) );

        // Background color for GUI and elements
        public Brush color_BG
        {
            get { return (Brush)GetValue(property_color_BG); }
            set { SetValue(property_color_BG, value); }
        }
        public static readonly DependencyProperty property_color_BG =
            DependencyProperty.Register(
            "color_BG", typeof(Brush), typeof(MainWindow),
            new UIPropertyMetadata(Brushes.Black) );

        // Color for Recording light
        public Brush color_rec
        {
            get { return (Brush)GetValue(property_color_rec); }
            set { SetValue(property_color_rec, value); }
        }
        public static readonly DependencyProperty property_color_rec =
            DependencyProperty.Register(
            "color_rec", typeof(Brush), typeof(MainWindow),
            new UIPropertyMetadata(Brushes.Red));

        // Color for battery
        public Brush color_bat
        {
            get { return (Brush)GetValue(property_color_bat); }
            set { SetValue(property_color_bat, value); }
        }
        public static readonly DependencyProperty property_color_bat =
            DependencyProperty.Register(
            "color_bat", typeof(Brush), typeof(MainWindow),
            new UIPropertyMetadata(Brushes.Orange));

        #endregion // GUI Colors

        #region GUI sizes

        // batt height
        public int s_batt_height
        {
            get { return (int)GetValue(property_s_batt_height); }
            set { SetValue(property_s_batt_height, value); }
        }
        public static readonly DependencyProperty property_s_batt_height =
            DependencyProperty.Register(
            "s_batt_height", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(42));
      

        // small height
        public int s_small_height
        {
            get { return (int)GetValue(property_s_small_height); }
            set { SetValue(property_s_small_height, value); }
        }
        public static readonly DependencyProperty property_s_small_height =
            DependencyProperty.Register(
            "s_small_height", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(42));

        // med height
        public int s_med_height
        {
            get { return (int)GetValue(property_s_med_height); }
            set { SetValue(property_s_med_height, value); }
        }
        public static readonly DependencyProperty property_s_med_height =
            DependencyProperty.Register(
            "s_med_height", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(48));

        // med width
        public int s_med_width
        {
            get { return (int)GetValue(property_s_med_width); }
            set { SetValue(property_s_med_width, value); }
        }
        public static readonly DependencyProperty property_s_med_width =
            DependencyProperty.Register(
            "s_med_width", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(170));
      
        // big height
        public int s_big_height
        {
            get { return (int)GetValue(property_s_big_height); }
            set { SetValue(property_s_big_height, value); }
        }
        public static readonly DependencyProperty property_s_big_height =
            DependencyProperty.Register(
            "s_big_height", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(64));   

        #endregion // GUI sizes

        #region GUI Variables
        /// <summary>
        /// Variables for displayed information of GUI
        /// Please prepend each variable with "d_"
        /// Please provide a DependencyProperty for each item
        ///   You can do this by typing "depprop" + TAB + TAB
        /// </summary>
        ///

        // Battery % remaining
        public int d_batteryLevel
        {
            get { return (int)GetValue(property_d_batteryLevel); }
            set { SetValue(property_d_batteryLevel, value); }
        }
        public static readonly DependencyProperty property_d_batteryLevel =
            DependencyProperty.Register(
            "d_batteryLevel", typeof(int), typeof(MainWindow),
            new UIPropertyMetadata(0));
        
        // Time of day
        public String d_Time
        {
            get { return (String)GetValue(property_d_Time); }
            set { SetValue(property_d_Time, value); }
        }
        public static readonly DependencyProperty property_d_Time =
            DependencyProperty.Register(
            "d_Time", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("00:00"));

        // Show Time on HUD?
        public Boolean d_showTime
        {
            get { return (Boolean)GetValue(property_d_showTime); }
            set { SetValue(property_d_showTime, value); }
        }
        public static readonly DependencyProperty property_d_showTime =
            DependencyProperty.Register(
            "d_showTime", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
        
        // speed
        public String d_speed
        {
            get { return (String)GetValue(property_d_speed); }
            set { SetValue(property_d_speed, value); }
        }
        public static readonly DependencyProperty property_d_speed =
            DependencyProperty.Register(
            "d_speed", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("0")); // 100 FOR TESTING

        // show speed?
        public Boolean d_showSpeed
        {
            get { return (Boolean)GetValue(property_d_showSpeed); }
            set { SetValue(property_d_showSpeed, value); }
        }
        public static readonly DependencyProperty property_d_showSpeed =
            DependencyProperty.Register(
            "d_showSpeed", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
      
        // latitude
        public String d_latitude
        {
            get { return (String)GetValue(property_d_latitude); }
            set { SetValue(property_d_latitude, value); }
        }
        public static readonly DependencyProperty property_d_latitude =
            DependencyProperty.Register(
            "d_latitude", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("000.0000000"));
      
        // longitude (
        public String d_longitude
        {
            get { return (String)GetValue(property_d_longitude); }
            set { SetValue(property_d_longitude, value); }
        }
        public static readonly DependencyProperty property_d_longitude =
            DependencyProperty.Register(
            "d_longitude", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("0000.0000000"));

        // show lat/long?
        public Boolean d_showLatLong
        {
            get { return (Boolean)GetValue(property_d_showLatLong); }
            set { SetValue(property_d_showLatLong, value); }
        }
        public static readonly DependencyProperty property_d_showLatLong =
            DependencyProperty.Register(
            "d_showLatLong", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(false));
        
        // altitude
        public String d_altitude
        {
            get { return (String)GetValue(property_d_altitude); }
            set { SetValue(property_d_altitude, value); }
        }
        public static readonly DependencyProperty property_d_altitude =
            DependencyProperty.Register(
            "d_altitude", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("0")); // 20000 FOR TESTING

        // show altitude?
        public Boolean d_showAlt
        {
            get { return (Boolean)GetValue(property_d_showAlt); }
            set { SetValue(property_d_showAlt, value); }
        }
        public static readonly DependencyProperty property_d_showAlt =
            DependencyProperty.Register(
            "d_showAlt", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
      

        // heading
        public String d_heading
        {
            get { return (String)GetValue(property_d_heading); }
            set { SetValue(property_d_heading, value); }
        }
        public static readonly DependencyProperty property_d_heading =
            DependencyProperty.Register(
            "d_heading", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("N"));

        // show heading?
        public Boolean d_showHeading
        {
            get { return (Boolean)GetValue(property_d_showHeading); }
            set { SetValue(property_d_showHeading, value); }
        }
        public static readonly DependencyProperty property_d_showHeading =
            DependencyProperty.Register(
            "d_showHeading", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
      

        // acceleration
        public String d_acceleration
        {
            get { return (String)GetValue(property_d_acceleration); }
            set { SetValue(property_d_acceleration, value); }
        }
        public static readonly DependencyProperty property_d_acceleration =
            DependencyProperty.Register(
            "d_acceleration", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("0.0"));

        // show acceleration
        public Boolean d_showAccel
        {
            get { return (Boolean)GetValue(property_d_showAccel); }
            set { SetValue(property_d_showAccel, value); }
        }
        public static readonly DependencyProperty property_d_showAccel =
            DependencyProperty.Register(
            "d_showAccel", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
      
        
        // temperature
        public String d_temp
        {
            get { return (String)GetValue(property_d_temp); }
            set { SetValue(property_d_temp, value); }
        }
        public static readonly DependencyProperty property_d_temp =
            DependencyProperty.Register(
            "d_temp", typeof(String), typeof(MainWindow),
            new UIPropertyMetadata("0"));

        // show temp?
        public Boolean d_showTemp
        {
            get { return (Boolean)GetValue(property_d_showTemp); }
            set { SetValue(property_d_showTemp, value); }
        }
        public static readonly DependencyProperty property_d_showTemp =
            DependencyProperty.Register(
            "d_showTemp", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));

        // show pretty ring?
        public Boolean d_showPretty
        {
            get { return (Boolean)GetValue(property_d_showPretty); }
            set { SetValue(property_d_showPretty, value); }
        }
        public static readonly DependencyProperty property_d_showPretty =
            DependencyProperty.Register(
            "d_showPretty", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));
      
        #endregion // GUI Variables

        #region Bookkeeping Variables
        /// <summary>
        /// Variables associated with device state
        /// Please prepend each variable with b_
        /// These generally shouldn't need DependencyProperties
        /// </summary>
        
        // receiving micro data?
        // Boolean receiving = false;

        // year, month, day
        String b_year = "0000", b_month = "00", b_day = "00";

        // hours, minutes, seconds
        String b_hours = "00", b_minutes = "00", b_seconds = "00";

        // log file name
        String b_fileName = "";

        // log point number
        int b_logPoint = 0;

        // logging data?
        public Boolean b_logging
        {
            get { return (Boolean)GetValue(property_b_logging); }
            set { SetValue(property_b_logging, value); }
        }
        public static readonly DependencyProperty property_b_logging =
            DependencyProperty.Register(
            "b_logging", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(false));

        // satellite coverage?
        public Boolean b_noSatCoverage
        {
            get { return (Boolean)GetValue(property_b_noSatCoverage); }
            set { SetValue(property_b_noSatCoverage, value); }
        }
        public static readonly DependencyProperty property_b_noSatCoverage =
            DependencyProperty.Register(
            "b_noSatCoverage", typeof(Boolean), typeof(MainWindow),
            new UIPropertyMetadata(true));

        // # of satellites
        int b_satellites = 0;

        // heading (degrees)
        double b_heading = 0;

        // altitude in meters
        double b_altMeters = 0;

        // light level (percentage)
        int b_lightLevel = 0;

        // hud is blank?
        Boolean b_blankHud = true;

        DisplayModes b_displayMode = DisplayModes.Minimal;

        WindowsWindow b_YawcamWindow = null;
        Boolean b_YawcamVisible = true;

        // file output
        StreamWriter outStream = null;

        // acceleration + peak hold counter
        double b_acceleration = 0;
        int b_accelHold = 0;

        #endregion Bookkeeping Variables

        public MainWindow()
        {
            InitializeComponent();
            hideYawcam();
            open_serial_port();
            drawDisplayMode();
        }

        #region Serial Port
        /// <summary>
        /// Code to instantiate a new serial port
        /// </summary>

        private SerialPort p = null;

        private void open_serial_port()
        {
            p = new SerialPort("COM1");
            p.BaudRate = 38400;
            p.Parity = Parity.None;
            p.StopBits = StopBits.One;
            p.DataBits = 8;
            p.Handshake = Handshake.None;
            p.ReadBufferSize = 16384;
            p.NewLine = "\r\n";
            p.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
            try
            {
                p.Open();
            }
            catch (Exception e)
            {
                System.Console.Write(e.Message);
                // Do not recover from this crash; close the program
                Environment.Exit(1);
            }
            try
            {
                p.WriteLine("q");
            }
            catch (Exception e)
            {
                System.Console.Write(e.Message);
                Environment.Exit(1);
            }
        }

        /// <summary>
        /// Event handler for received serial data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp1 = (SerialPort)sender;
            Dispatcher.Invoke(DispatcherPriority.Send, new Action<String>(update_hud), sp1.ReadLine());
            //sp1.ReadExisting(); // FIXED IT, BITCHES!!!!
        }
        #endregion // Serial Port

        #region Update HUD Function
        /// <summary>
        /// Takes serial line (command from microcontroller),
        /// Decodes it, and updates necessary fields
        /// </summary>
        /// <param name="serial_entry"></param>
        private void update_hud(String serial_entry)
        {
            serial_entry = serial_entry.Trim();
            String[] parsed = serial_entry.Split(' ');
            // switch on first word
            switch (parsed[0])
            {
                case "Sleep":
                    if (parsed[1].Equals("ENTER"))
                    {
                        if (b_logging)
                        {
                            close_LogFile(outStream);
                            outStream = null;
                            b_logging = false;
                        }
                        // exit the program on sleep
                        System.Diagnostics.Process.Start("shutdown", "/s /t 0");
                        //System.Environment.Exit(1);
                    }
                    break;
                case "Accel":
                    color_Text = Brushes.Lime;
                    #region Peak-Hold Acceleration
                    if (b_accelHold == 0)
                    {
                        // If not holding, reduce measured acceleration by x
                        b_acceleration -= 0.5;
                    }
                    else
                    {
                        // If holding, reduce hold count
                        b_accelHold--;
                    }
                    double tempAccel = System.Convert.ToDouble(parsed[1]);
                    if (tempAccel >= b_acceleration)
                    {
                        b_acceleration = tempAccel;
                        b_accelHold = 4; // hold for x tenths of a second
                    }
                    d_acceleration = String.Format( "{0:f1}", b_acceleration);
                    #endregion // Peak-Hold Acceleration
                    break;
                case "Avges":
                    d_temp = parsed[2].Split('.')[0];
                    #region Light Level Switch
                    b_lightLevel = System.Convert.ToInt16(parsed[3]);
                    if (b_lightLevel > 8)
                    {
                        // highest brightness
                    }
                    else if (b_lightLevel > 6)
                    {
                        // high-mid brightness
                    }
                    else if (b_lightLevel > 4)
                    {
                        // mid brightness
                    }
                    else if (b_lightLevel > 2)
                    {
                        // low-mid brightness
                    }
                    else
                    {
                        // lowest brightness
                    }
                    #endregion // Light lEvel Switch
                    break;
                case "GPSTM":
                    #region Update Time/Date
                    // break if no time
                    if (parsed[1].Equals("Time")) break;
                    String[] parseddate = parsed[1].Split('/');
                    b_year = parseddate[0];
                    b_month = parseddate[1];
                    b_day = parseddate[2];
                    String[] parsedtime = parsed[2].Split(':');
                    int hrs = System.Convert.ToInt16(parsedtime[0]);
                    hrs = hrs - 4;
                    if (hrs < 0) hrs += 24;
                    b_hours = System.Convert.ToString(hrs);
                    b_minutes = parsedtime[1];
                    b_seconds = parsedtime[2].Split('.')[0];
                    d_Time = b_hours + ":" + b_minutes;
                    #endregion // Update Time/Date
                    break;
                case "GPSLN":
                    // Do not update if no satellite coverage
                    if (b_noSatCoverage) { break; }
                    #region Update GPS Info
                    // SPEED
                    d_speed = parsed[5].Split('.')[0];
                    // ALTITUDE
                    double altFeet = System.Convert.ToDouble(parsed[4]);
                    d_altitude = System.Convert.ToString(altFeet);
                    b_altMeters = altFeet * 0.3048;
                    // POSITION
                    d_latitude = parsed[2];
                    d_longitude = parsed[3];
                    // SAT COVERAGE
                    b_satellites = System.Convert.ToInt32(parsed[8]);
                    // DIRECTION
                    b_heading = System.Convert.ToDouble(parsed[7]);
                    #region Heading Conversion
                    if ((b_heading >= 337.5) || (b_heading < 22.5))
                    {
                        d_heading = "N";
                    }
                    else if ((b_heading >= 22.5) && (b_heading < 67.5))
                    {
                        d_heading = "NE";
                    }
                    else if ((b_heading >= 67.5) && (b_heading < 112.5))
                    {
                        d_heading = "E";
                    }
                    else if ((b_heading >= 112.5) && (b_heading < 157.5))
                    {
                        d_heading = "SE";
                    }
                    else if ((b_heading >= 157.5) && (b_heading < 202.5))
                    {
                        d_heading = "S";
                    }
                    else if ((b_heading >= 202.5) && (b_heading < 247.5))
                    {
                        d_heading = "SW";
                    }
                    else if ((b_heading >= 247.5) && (b_heading < 292.5))
                    {
                        d_heading = "W";
                    }
                    else if ((b_heading >= 292.5) && (b_heading < 337.5))
                    {
                        d_heading = "NW";
                    }
                    #endregion // Heading Conversion
                    #endregion // Update GPS Info
                    // LOGGING
                    if (b_logging && outStream != null && !b_noSatCoverage) {
                        log_data(outStream); 
                    }
                    break;
                case "FGvlt":
                    // low volt thresh warning
                    double voltage = System.Convert.ToDouble(parsed[1]);
                    if (voltage < 15)
                    {
                        // warn!
                        color_bat = Brushes.Yellow;
                    }
                    else
                    {
                        color_bat = color_Text;
                    }
                    break;
                case "FGabs":
                    // fuel gauge absolute remaining
                    //d_batteryLevel = System.Convert.ToInt32(parsed[1]) / 5500; // mAh
                    break;
                case "FGrel":
                    // fuel gauge relative % remaining
                    d_batteryLevel = System.Convert.ToInt16(parsed[1]);
                    break;
                case "Buttn":
                    #region ID Button Press
                    switch (parsed[1])
                    {
                        case "M":
                            // middle button
                            // blank hud
                            blankHud();
                            break;
                        case "U":
                            // up button
                            // log data
                            #region LogButton
                            if (!b_logging)
                            {
                                try
                                {
                                    outStream = make_NewLogFile();
                                    b_logging = true;
                                }
                                catch // (Exception e)
                                {
                                    outStream = null;
                                    b_logging = false;
                                }
                            }
                            else
                            {
                                close_LogFile(outStream);
                                outStream = null;
                                b_logging = false;
                            }
                            #endregion // LogButton
                            break;
                        case "D":
                            // down button
                            // rear view
                            rearView();
                            break;
                        case "L":
                            // left button
                            // mode up
                            nextDisplayMode();
                            if (!b_blankHud) drawDisplayMode();
                            break;
                        case "R":
                            // right button
                            // mode down
                            prevDisplayMode();
                            if (!b_blankHud) drawDisplayMode();
                            break;
                        case "0":
                            // unknown button
                            break;
                        default:
                            // unknown button?
                            break;
                    }
                    #endregion // ID Button Press
                    break;
                case "GPSST":
                    #region Update Sat Coverage
                    if (parsed[1].Equals("Doing"))
                    {
                        b_noSatCoverage = false; // sat coverage
                    }
                    else
                    {
                        b_noSatCoverage = true; // no sat coverage
                    }
                    #endregion // Update Sat Coverage
                    break;
                case "Error":
                    #region Error
                    if (parsed[1].Equals("GPS") && parsed[2].Equals("failure"))
                    {
                        b_noSatCoverage = true;
                    }
                    break;
                    #endregion // Error
                default:
                    // unknown case
                    break;
            } // switch (parsed[0])
        } // update_hud
        #endregion // Update HUD Function

        #region Rear View Yawcam Functions

        void hideYawcam()
        {
            if (b_YawcamVisible == true)
            {
                WindowsWindows wndList = new WindowsWindows(false, false);
                foreach (WindowsWindow wnd in wndList)
                {
                    if (wnd.Title.Contains("Preview"))
                    {
                        wnd.Visible = false;
                        b_YawcamVisible = false;
                        b_YawcamWindow = wnd;
                    }
                }
            }
        }

        void showYawcam()
        {
            if (b_YawcamVisible == false)
            {
                b_YawcamVisible = true;
                b_YawcamWindow.Visible = true;
                b_YawcamWindow.Activate();
            }
        }

        void hideYawcamEvent( object source, ElapsedEventArgs e) {
            hideYawcam();
            timer.Close();
            timer = null;
        }

        #endregion // Rear View Yawcam Functions

        #region Button Functions

        Timer timer = null;

        void rearView()
        {
            if (b_YawcamVisible == false && timer == null)
            {
                showYawcam();
                timer = new Timer();
                timer.Elapsed += new ElapsedEventHandler( hideYawcamEvent );
                timer.Interval = 3000;
                timer.Enabled = true;
                timer.Start();
            }
        }

        void blankHud()
        {
            if (b_blankHud)
            {
                // call appropriate display mode
                b_blankHud = false;
                drawDisplayMode();
            }
            else
            {
                // hide all data except battery and rec light
                b_blankHud = true;
                drawDisplayMode();
            }
        }

        void drawDisplayMode()
        {
            if (b_blankHud)
            {
                d_showPretty = false;
                d_showSpeed = false;
                d_showAccel = false;
                d_showAlt = false;
                d_showHeading = false;
                d_showLatLong = false;
                d_showTemp = false;
                d_showTime = false;
                return;
            }
            switch (b_displayMode)
            {
                case DisplayModes.Beginning:
                case DisplayModes.End:
                    d_showPretty = false;
                    d_showSpeed = false;
                    d_showAccel = false;
                    d_showAlt = false;
                    d_showHeading = false;
                    d_showLatLong = false;
                    d_showTemp = false;
                    d_showTime = false;
                    break;
                case DisplayModes.Normal:
                    d_showPretty = true;
                    d_showSpeed = true;
                    d_showAccel = true;
                    d_showAlt = true;
                    d_showHeading = true;
                    d_showLatLong = false;
                    d_showTemp = true;
                    d_showTime = true;
                    break;
                case DisplayModes.Minimal:
                    // move speed display for this one?
                    d_showPretty = false;
                    d_showSpeed = true;
                    d_showAccel = false;
                    d_showAlt = false;
                    d_showHeading = true;
                    d_showLatLong = false;
                    d_showTemp = false;
                    d_showTime = false;
                    break;
                case DisplayModes.GeoCache:
                    d_showPretty = false;
                    d_showSpeed = false;
                    d_showAccel = false;
                    d_showHeading = true;
                    d_showLatLong = true;
                    d_showTemp = false;
                    d_showTime = true;
                    break;
                default:
                    d_showPretty = false;
                    d_showSpeed = false;
                    d_showAccel = false;
                    d_showAlt = false;
                    d_showHeading = false;
                    d_showLatLong = false;
                    d_showTemp = false;
                    d_showTime = false;
                    break;
            }
        }

        void nextDisplayMode()
        {
            b_displayMode += 1;
            if (b_displayMode == DisplayModes.End)
            {
                b_displayMode = DisplayModes.Beginning + 1;
            }
        }

        void prevDisplayMode()
        {
            b_displayMode -= 1;
            if (b_displayMode == DisplayModes.Beginning)
            {
                b_displayMode = DisplayModes.End - 1;
            }
        }

        #endregion // Button Functions

        #region Log File Output

        /// <summary>
        /// Creates a data log entry in the output stream
        /// </summary>
        /// <param name="stream"></param>
        void log_data(StreamWriter stream)
        {
            b_logPoint++;
            {
                stream.Write("<Placemark>\r\n"
                    + "<description><![CDATA[<i>Point #" + b_logPoint
                    + "<br>Time: " + d_Time
                    + "<br>Acceleration: " + d_acceleration + " g's"
                    + "<br>Temperature: " + d_temp + " celsius"
                    + "<br>Latitude: " + d_latitude + " deg"
                    + "<br>Longitude: " + d_longitude + " deg"
                    + "<br>Altitude: " + d_altitude + " ft"
                    + "<br>Speed: " + d_speed + " mi/hr"
                    + "<br>Heading: " + b_heading + " deg"
                    + "<br>Fix indicator: 3-D"
                    + "<br>Used SVs: " + b_satellites
                    + "</i>]]></description>\r\n"
                    + "<styleUrl>#dot</styleUrl>\r\n"
                    + "<Point><coordinates>" + d_longitude + "," + d_latitude + "," + System.Convert.ToString(b_altMeters)
                    + "</coordinates></Point>\r\n"
                    + "</Placemark>\r\n");
            }
        }

        /// <summary>
        /// Creates a new log file and returns the output stream
        /// </summary>
        /// <returns></returns>
        StreamWriter make_NewLogFile()
        {
            b_fileName = "log_" +
                        System.Convert.ToString(b_year) +
                        "-" +
                        String.Format("{0:d2}", b_month) +
                        "-" +
                        String.Format("{0:d2}", b_day) +
                        "_" +
                        String.Format("{0:d2}", b_hours) +
                        "-" +
                        String.Format("{0:d2}", b_minutes) +
                        "-" +
                        String.Format("{0:d2}", b_seconds);
            String path = "D:\\" + b_fileName + ".kml";
            StreamWriter stream = new StreamWriter(path);
            {
                stream.Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
                    + "<kml xmlns=\"http://earth.google.com/kml/2.2\">\r\n"
                    + "<Document>\r\n"
                    + "<name></name>\r\n"
                    + "<Style id=\"docIcon\">\r\n"
                    + "<ListStyle>\r\n"
                    + "<ItemIcon><href>C:\\Users\\Aditya\\AppData\\Roaming\\Trimble Navigation\\Trimble GPS Monitor\\0000FF.png</href></ItemIcon>\r\n"
                    + "<listItemType>checkHideChildren</listItemType>\r\n"
                    + "</ListStyle>\r\n"
                    + "</Style>\r\n"
                    + "<styleUrl>#docIcon</styleUrl>\r\n"
                    + "<Folder>\r\n"
                    + "<name>Points</name>\r\n"
                    + "<Style id=\"folderStyle\">\r\n"
                    + "<ListStyle>\r\n"
                    + "<ItemIcon><href>C:\\Users\\Aditya\\AppData\\Roaming\\Trimble Navigation\\Trimble GPS Monitor\\0000FF.png</href></ItemIcon>\r\n"
                    + "<listItemType>checkHideChildren</listItemType>\r\n"
                    + "</ListStyle>\r\n"
                    + "</Style>\r\n"
                    + "<styleUrl>#folderStyle</styleUrl>\r\n"
                    + "<Style id=\"dot\">\r\n"
                    + "<IconStyle>\r\n"
                    + "<Icon><href>C:\\Users\\Aditya\\AppData\\Roaming\\Trimble Navigation\\Trimble GPS Monitor\\pointIcon.png</href></Icon>\r\n"
                    + "<color>00FF00FF</color>\r\n"
                    + "<colorMode>normal</colorMode>\r\n"
                    + "<scale>0.40</scale>\r\n"
                    + "<hotSpot x=\"0.5\" xunits=\"fraction\" y=\"0.5\" yunits=\"fraction\" />\r\n"
                    + "</IconStyle>\r\n"
                    + "<BalloonStyle>\r\n"
                    + "<textColor>FF800000</textColor>\r\n"
                    + "<bgColor>FFFFEFEF</bgColor>\r\n"
                    + "<text><![CDATA[<font size=+1><b><u>Details</u></b><br></font>]]>$[description]</text>\r\n"
                    + "</BalloonStyle>\r\n"
                    + "</Style>\r\n");
                return stream;
            }
        }

        /// <summary>
        /// Cleans up the file and closes the output stream
        /// </summary>
        /// <param name="stream"></param>
        void close_LogFile(StreamWriter stream)
        {
            stream.Write("</Folder>\r\n"
                + "</Document>\r\n"
                + "</kml>\r\n");
            stream.Close();
        }

        #endregion // Log File Output

    } // class MainWindow
}
